// 空方法
export function noop () { }
// 判断是否是此对象上的实例属性
export function hasOwnProp (obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}
// 判断数据类型
export function protoType (value) {
  return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}
// 判断指定参数是否是一个纯粹的对象
export function isPlainObject (obj) {
  if (!obj || protoType(obj) !== 'object') {
    return false;
  }
  const proto = Object.getPrototypeOf(obj);
  if (!proto) {
    return true;
  }
  const ctor = hasOwnProp(proto, 'constructor') && proto.constructor;
  const fnToString = Object.hasOwnProperty.toString;
  return typeof ctor === 'function' && fnToString.call(ctor) === fnToString.call(Object);
}
// 判断是否为类数组
export function isArrayLike (o) {
  return o && typeof o === 'object' && isFinite(o.length) && o.length >= 0 && o.length === Math.floor(o.length) && o.length < 4294967296;
}
// 判断是否为function
export function isFunction (value) {
  return protoType(value) === 'function';
}
// 判断是否为object
export function isObject (value) {
  return protoType(value) === 'object';
}
// 是否为数组
export function isArray (value) {
  return protoType(value) === 'array';
}
// 判断是否为number
export function isNumber (value) {
  return protoType(value) === 'number';
}
// 判断是否为promise对象
export function isPromise (value) {
  return !!value && (typeof value === 'object' || typeof value === 'function') && typeof value.then === 'function';
}
// 类数组转数组
export function toArray (value) {
  return isArrayLike(value) ? Array.prototype.slice.call(value) : [];
}
// 转合法date对象
export function toDate (date) {
  if (!date) return;
  const isValidDate = function (date) {
    return !/Invalid|NaN/.test((protoType(date) === 'date' ? date : new Date(date)).toString());
  };
  if (typeof date === 'string') {
    if (/^\d*$/.test(date)) {
      date = Number(date);
    } else if (!isValidDate(date)) {
      date = date.replace(/-/g, '/').replace(/(\.0)$/, '');
    }
  }
  if (isValidDate(date)) {
    return protoType(date) === 'date' ? date : new Date(date);
  }
}
// 去掉字符串2边空格
export function trim (str) {
  return (str || str === 0) ? String(str).trim() : '';
}
// 数组和对象循环
export function each (obj, callback) {
  if (!obj) return;
  if (isArrayLike(obj)) {
    for (let i = 0, len = obj.length; i < len; i++) {
      if (callback(obj[i], i, obj) === false) {
        break;
      }
    }
  } else {
    for (const key of Object.keys(obj)) {
      if (callback(obj[key], key, obj) === false) {
        break;
      }
    }
  }
}
// 对象拷贝克隆，覆盖传值
export function extend (...args) {
  let options; let name; let src; let copy; let copyIsArray; let clone;
  let target = args[0] || {};
  let i = 1;
  const length = args.length;
  let deep = false;
  // Handle a deep copy situation
  if (typeof target === 'boolean') {
    deep = target;
    // Skip the boolean and the target
    target = args[i] || {};
    i++;
  }
  // Handle case when target is a string or something (possible in deep copy)
  if (typeof target !== 'object' && !isFunction(target)) {
    target = {};
  }
  for (; i < length; i++) {
    // Only deal with non-null/undefined values
    if ((options = args[i]) != null) {
      // Extend the base object
      for (name in options) {
        copy = options[name];
        // Prevent Object.prototype pollution
        // Prevent never-ending loop
        if (name === '__proto__' || target === copy) {
          continue;
        }
        // Recurse if we're merging plain objects or arrays
        if (deep && copy && (isPlainObject(copy) ||
          (copyIsArray = isArray(copy)))) {
          src = target[name];
          // Ensure proper type for the source value
          if (copyIsArray && !isArray(src)) {
            clone = [];
          } else if (!copyIsArray && !isPlainObject(src)) {
            clone = {};
          } else {
            clone = src;
          }
          copyIsArray = false;
          // Never move original objects, clone them
          target[name] = extend(deep, clone, copy);
          // Don't bring in undefined values
        } else if (copy !== undefined) {
          target[name] = copy;
        }
      }
    }
  }
  // Return the modified object
  return target;
}
// repeat
export function repeat (str, num) {
  num = parseInt(num) || 0;
  return num ? new Array(num + 2).join(String(str)) : '';
}
// padStart
export function padStart (str, num, padStr) {
  return new Array(num - String(str).length + 1).join(String(padStr)) + str;
}
// padEnd
export function padEnd (str, num, padStr) {
  return String(str) + new Array(num - String(str).length + 1).join(String(padStr));
}
